home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!cs.utexas.edu!rutgers!aramis.rutgers.edu!dartagnan.rutgers.edu!mcgrew
- From: mcgrew@dartagnan.rutgers.edu (Charles Mcgrew)
- Newsgroups: comp.sources.sun
- Subject: v01i033: Cknfs - Test NFS paths for validity
- Message-ID: <Jun.21.13.31.16.1989.29033@dartagnan.rutgers.edu>
- Date: 21 Jun 89 17:31:18 GMT
- Organization: Rutgers Univ., New Brunswick, N.J.
- Lines: 606
- Approved: mcgrew@aramis.rutgers.edu
-
- Submitted-by: aklietz@ncsa.uiuc.edu
- Posting-number: Volume 1, Issue 33
- Archive-name: cknfs
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: cknfs.c
- # Wrapped by aklietz@occam on Wed May 31 18:25:22 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'cknfs.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cknfs.c'\"
- else
- echo shar: Extracting \"'cknfs.c'\" \(13080 characters\)
- sed "s/^X//" >'cknfs.c' <<'END_OF_FILE'
- X/*
- X * cknfs - Check for dead NFS servers
- X *
- X * Don't you hate it when you login to an NFS client, only to find
- X * yourself hung because one of your paths points to a dead NFS server?
- X * Well, this program fixes that problem. It takes a list of execution
- X * paths as arguments. Each path is examined for an NFS mount point.
- X * If found, the corresponding NFS server is checked. Paths that lead
- X * to dead NFS servers are ignored. The remaining paths are printed to
- X * stdout. No more hung logins!
- X *
- X * Usage: cknfs -e -s -t# -v -D -L paths
- X *
- X * -e silent, do not print paths
- X * -s print paths in sh format (colons)
- X * -t n timeout interval before assuming an NFS
- X * server is dead (default 10 seconds)
- X * -v verbose
- X * -D debug
- X * -L expand symbolic links
- X *
- X * Typical examples:
- X *
- X * set path = `cknfs /bin /usr/bin /usr/ucb . /usr6/bin /sdg/bin`
- X * alias cd 'cknfs -e \!*; if ($status == 0) chdir \!*'
- X *
- X * The latter example prevents you from hanging if you cd to a
- X * directory that leads to a dead NFS server.
- X *
- X * Adminstrative note: You can still get hung if your administator
- X * mixes NFS mount points from different machines in the same parent
- X * directory or if your administrator mixes regular directories and
- X * NFS mount points in the same parent directory.
- X *
- X * The best organization is an overall /nfs directory with subdirectories
- X * for each machine. For example, if you have 3 NFS servers named
- X * "newton", "bardeen", and "zaphod", a good organization would be
- X *
- X * /nfs/bardeen/apps
- X * /nfs/bardeen/bin
- X * /nfs/newton/bin
- X * /nfs/newton/local
- X * /nfs/zaphod/bin
- X * /nfs/zaphod/sdg
- X *
- X * NEVER MIX MOUNT POINTS FROM DIFFERENT MACHINES IN THE SAME
- X * PARENT DIRECTORY! Follow this rule and use this program and
- X * you will never get hung by NFS again.
- X */
- X
- X/*
- X * Copyright (c) 1988, The Board of Trustees of the University of Illinois
- X * National Center for Supercomputing Applications.
- X *
- X * No warranty is expressed or implied.
- X * Unlimited redistribution permitted.
- X *
- X */
- X
- Xstatic char *RCSid = "$Header: cknfs.c,v 1.4 89/05/31 18:24:49 aklietz Exp $";
- X
- X/*
- X * $Log: cknfs.c,v $
- X * Revision 1.4 89/05/31 18:24:49 aklietz
- X * Fix bug introduced in rev 1.3 that did hangable lstat before
- X * checking for NFS mount point.
- X * Add support for Ultrix.
- X *
- X * Revision 1.3 89/05/29 03:30:55 aklietz
- X * Terminate silently if no args in -e mode.
- X * Fix omission of chdir("/") during parse of symlink to absolute path.
- X *
- X * Revision 1.2 89/05/26 14:14:35 aklietz
- X * Baseline for release
- X *
- X * Revision 1.1 89/05/26 13:37:39 aklietz
- X * Initial revision
- X *
- X */
- X
- X#include <sys/param.h>
- X#include <errno.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <signal.h>
- X#include <ctype.h>
- X#include <stdio.h>
- X#include <sys/time.h>
- X#include <sys/socket.h>
- X#include <arpa/inet.h>
- X#include <netdb.h>
- X#include <rpc/rpc.h>
- X#include <rpc/pmap_prot.h>
- X#include <rpc/pmap_clnt.h>
- X#include <nfs/nfs.h>
- X
- X/*
- X * Make initial program
- X * May 1989, Alan Klietz (aklietz@ncsa.uiuc.edu)
- X */
- X
- X#define DEFAULT_TIMEOUT 10 /* Default timeout for checking NFS server */
- X
- Xextern char *realloc();
- Xextern char *strchr(), *strrchr(), *strtok();
- X
- Xstruct m_mlist {
- X int mlist_checked; /* -1 if bad, 0 if not checked, 1 if ok */
- X struct m_mlist *mlist_next;
- X char *mlist_dir;
- X char *mlist_fsname;
- X int mlist_isnfs;
- X};
- Xstatic struct m_mlist *firstmnt;
- X
- Xstatic int errflg;
- Xstatic int eflg, sflg, vflg, Dflg, Lflg;
- Xstatic int timeout = DEFAULT_TIMEOUT;
- Xstatic char prefix[MAXPATHLEN];
- Xstruct m_mlist *isnfsmnt();
- Xchar *xalloc();
- Xvoid mkm_mlist();
- X
- Xint
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X register int n;
- X register char *s;
- X int good = 0;
- X char outbuf[BUFSIZ];
- X char errbuf[BUFSIZ];
- X extern int optind;
- X extern char *optarg;
- X
- X
- X /*
- X * Avoid intermixing stdout and stderr
- X */
- X setvbuf(stdout, outbuf, _IOFBF, sizeof(outbuf));
- X setvbuf(stderr, errbuf, _IOLBF, sizeof(errbuf));
- X
- X while ((n = getopt(argc, argv, "est:vDL")) != EOF)
- X switch(n) {
- X case 'e': ++eflg;
- X break;
- X
- X case 's': ++sflg;
- X break;
- X
- X case 't': timeout = atoi(optarg);
- X break;
- X
- X case 'v': ++vflg;
- X break;
- X
- X case 'D': ++Dflg; ++vflg;
- X break;
- X
- X case 'L': ++Lflg;
- X break;
- X
- X default:
- X ++errflg;
- X }
- X
- X if (argc <= optind && !eflg) /* no paths */
- X ++errflg;
- X
- X if (errflg) {
- X fprintf(stderr, "Usage: %s -e -s -t# -v -D -L paths\n", argv[0]);
- X fprintf(stderr, "\tCheck paths for dead NFS servers\n");
- X fprintf(stderr, "\tGood paths are printed to stdout\n\n");
- X fprintf(stderr, "\t -e\tsilent, do not print paths\n");
- X fprintf(stderr, "\t -s\tprint paths in sh format (semicolons)\n");
- X fprintf(stderr, "\t -t n\ttimeout interval before assuming an NFS\n");
- X fprintf(stderr, "\t\tserver is dead (default 10 seconds)\n");
- X fprintf(stderr, "\t -v\tverbose\n");
- X fprintf(stderr, "\t -D\tdebug\n");
- X fprintf(stderr, "\t -L\texpand symbolic links\n\n");
- X exit(1);
- X }
- X
- X for (n = optind; n < argc; ++n) {
- X s = argv[n];
- X if (Dflg)
- X fprintf(stderr, "chkpath(%s)\n", s);
- X if (chkpath(s)) {
- X if (good++ && !eflg)
- X putchar(sflg ? ':' : ' ');
- X if (!eflg)
- X fputs(Lflg ? prefix : s, stdout);
- X } else
- X if (vflg)
- X fprintf(stderr, "path skipped: %s\n",
- X Lflg ? prefix : s);
- X }
- X
- X if (good && !eflg)
- X putchar('\n');
- X
- X fflush(stderr);
- X fflush(stdout);
- X
- X exit(good == 0 && optind < argc );
- X}
- X
- X
- Xint chkpath(path)
- X/*
- X * Check path for accessibility. Return 1 if ok, 0 if error
- X */
- Xchar *path;
- X{
- X if (*path != '/') { /* If not absolute path, get initial prefix */
- X if (getwd(prefix) < 0) {
- X fprintf(stderr, "%s\n", prefix);
- X return 0;
- X }
- X }
- X return(_chkpath(path));
- X}
- X
- X
- X#define NTERMS 256
- X
- Xint
- X_chkpath(path)
- Xchar *path;
- X{
- X register char *s, *s2;
- X register int i, front=0, back=0;
- X struct stat stb;
- X struct m_mlist *mlist;
- X char p[MAXPATHLEN];
- X char symlink[MAXPATHLEN];
- X char *queue[NTERMS];
- X
- X
- X /*
- X * Copy path to working storage
- X */
- X strncpy(p, path, sizeof(p)-1);
- X
- X if (*p == '/') { /* If absolute path, start at root */
- X *prefix = '\0';
- X (void) chdir("/");
- X }
- X
- X if (Dflg)
- X fprintf(stderr, "_chkpath(%s) prefix=%s\n", path, prefix);
- X
- X /*
- X * Put directory terms on FIFO queue
- X */
- X for (s = strtok(p, "/"); s != NULL; s = strtok(NULL, "/")) {
- X if (back >= NTERMS) {
- X fprintf(stderr, "Too many subdirs: %s\n", path);
- X goto fail;
- X }
- X queue[back++] = s;
- X }
- X /* queue[front] = a, queue[front+1] = b, ... queue[back] = null */
- X
- X /*
- X * Scan queue of directory terms, expanding
- X * symbolic links recursively.
- X */
- X while (front != back) {
- X s = queue[front++];
- X /* Dot */
- X if (s[0] == '.' && s[1] == '\0')
- X continue;
- X /* Dot Dot */
- X if (s[0] == '.' && s[1] == '.' && s[2] == '\0') {
- X if (chdir("..") < 0) {
- X perror("chdir(..)");
- X goto fail;
- X }
- X /* Remove trailing component of prefix */
- X if ((s2 = strrchr(prefix, '/')) != NULL)
- X *s2 = '\0';
- X continue;
- X } else {
- X strcat(prefix, "/");
- X strcat(prefix, s);
- X }
- X
- X if ((mlist = isnfsmnt(prefix)) != NULL) /* NFS mount? */
- X if (chknfsmnt(mlist) <= 0)
- X return 0;
- X
- X /* Check if symlink */
- X if (lstat(s, &stb) < 0) {
- X perror(s);
- X goto fail;
- X }
- X if ((stb.st_mode & S_IFMT) != S_IFLNK) {
- X /* not symlink */
- X if (chdir(s) < 0) {
- X fprintf(stderr, "chdir(%s): ", s);
- X perror("");
- X goto fail;
- X }
- X continue;
- X }
- X
- X /* Remove symlink from tail of prefix */
- X if ((s2 = strrchr(prefix, '/')) != NULL)
- X *s2 = '\0';
- X /*
- X * Read symlink
- X */
- X if ((i = readlink(s, symlink, MAXPATHLEN-1)) < 0) {
- X perror(s);
- X goto fail;
- X }
- X symlink[i] = '\0'; /* null terminate */
- X
- X /*
- X * Recursively check symlink
- X */
- X if (_chkpath(symlink) == 0)
- X return 0;
- X }
- X
- X return 1;
- X
- Xfail:
- X return 0;
- X}
- X
- X
- Xstruct m_mlist *
- Xisnfsmnt(path)
- X/*
- X * Return 1 if path is NFS mount point
- X */
- Xchar *path;
- X{
- X register struct m_mlist *mlist;
- X static int init;
- X
- X if (init == 0) {
- X ++init;
- X mkm_mlist();
- X }
- X
- X for (mlist = firstmnt; mlist != NULL; mlist = mlist->mlist_next) {
- X if (mlist->mlist_isnfs == 0)
- X continue;
- X if (strcmp(mlist->mlist_dir, path) == 0)
- X return(mlist);
- X }
- X return NULL;
- X}
- X
- X
- Xstatic int
- Xget_inaddr(saddr, host)
- X/*
- X * Translate host name to Internet address.
- X * Return 1 if ok, 0 if error
- X */
- Xstruct sockaddr_in *saddr;
- Xchar *host;
- X{
- X register struct hostent *hp;
- X
- X memset((char *)saddr, 0, sizeof(struct sockaddr_in));
- X saddr->sin_family = AF_INET;
- X if ((saddr->sin_addr.s_addr = inet_addr(host)) == -1) {
- X if ((hp = gethostbyname(host)) == NULL) {
- X fprintf(stderr, "%s: unknown host\n", host);
- X return 0;
- X }
- X memcpy((char *)&saddr->sin_addr, hp->h_addr, hp->h_length);
- X }
- X return 1;
- X}
- X
- X
- Xint
- Xchknfsmnt(mlist)
- X/*
- X * Ping the NFS server indicated by the given mnt entry
- X */
- Xregister struct m_mlist *mlist;
- X{
- X register char *s;
- X register struct m_mlist *mlist2;
- X CLIENT *client;
- X struct sockaddr_in saddr;
- X int sock, len;
- X struct timeval tottimeout;
- X struct timeval interval;
- X int prognum, vers, port;
- X struct pmap pmap;
- X enum clnt_stat rpc_stat;
- X static char p[MAXPATHLEN];
- X
- X if (Dflg)
- X fprintf(stderr, "chknfsmnt(%s)\n", mlist->mlist_fsname);
- X
- X if (mlist->mlist_checked) /* if already checked this mount point */
- X return (mlist->mlist_checked);
- X
- X /*
- X * Save path to working storage and strip colon
- X */
- X strncpy(p, mlist->mlist_fsname, sizeof(p)-1);
- X if ((s = strchr(p, ':')) != NULL)
- X *s = '\0';
- X len = strlen(p);
- X
- X /*
- X * See if remote host already checked via another mount point
- X */
- X for (mlist2 = firstmnt; mlist2 != NULL; mlist2 = mlist2->mlist_next)
- X if (strncmp(mlist2->mlist_fsname, p, len) == 0
- X && mlist2->mlist_checked)
- X return(mlist2->mlist_checked);
- X
- X mlist->mlist_checked = -1; /* set failed */
- X if (vflg)
- X fprintf(stderr, "Checking %s..\n", p);
- X interval.tv_sec = 2; /* retry interval */
- X interval.tv_usec = 0;
- X
- X /*
- X * Parse internet address
- X */
- X if (get_inaddr(&saddr, p) == 0)
- X return 0;
- X /*
- X * Get socket to remote portmapper
- X */
- X saddr.sin_port = htons(PMAPPORT);
- X sock = RPC_ANYSOCK;
- X if ((client = clntudp_create(&saddr, PMAPPROG, PMAPVERS, interval,
- X &sock)) == NULL) {
- X clnt_pcreateerror(p);
- X return 0;
- X }
- X /*
- X * Query portmapper for port # of NFS server
- X */
- X pmap.pm_prog = NFS_PROGRAM;
- X pmap.pm_vers = NFS_VERSION;
- X pmap.pm_prot = IPPROTO_UDP;
- X pmap.pm_port = 0;
- X tottimeout.tv_sec = timeout; /* total timeout */
- X tottimeout.tv_usec = 0;
- X if ((rpc_stat = clnt_call(client, PMAPPROC_GETPORT, xdr_pmap, &pmap,
- X xdr_u_int, &port, tottimeout)) != RPC_SUCCESS) {
- X clnt_perror(client, p);
- X clnt_destroy(client);
- X return 0;
- X }
- X clnt_destroy(client);
- X
- X if (port == 0) {
- X fprintf(stderr, "%s: NFS server not registered\n", p);
- X return 0;
- X }
- X /*
- X * Get socket to NFS server
- X */
- X saddr.sin_port = htons(port);
- X sock = RPC_ANYSOCK;
- X if ((client = clntudp_create(&saddr, NFS_PROGRAM, NFS_VERSION,
- X interval, &sock)) == NULL) {
- X clnt_pcreateerror(p);
- X return 0;
- X }
- X /*
- X * Ping NFS server
- X */
- X tottimeout.tv_sec = timeout;
- X tottimeout.tv_usec = 0;
- X if ((rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
- X xdr_void, (char *)NULL, tottimeout)) != RPC_SUCCESS) {
- X clnt_perror(client, p);
- X clnt_destroy(client);
- X return 0;
- X }
- X clnt_destroy(client);
- X mlist->mlist_checked = 1; /* set success */
- X if (vflg)
- X fprintf(stderr, "%s ok\n", p);
- X return 1;
- X}
- X
- X
- Xchar *
- Xxalloc(size)
- X/*
- X * Alloc memory with error checks
- X */
- Xunsigned int size;
- X{
- X register char *mem;
- X char *malloc();
- X
- X if ((mem = (char *)malloc(size)) == NULL) {
- X (void) fprintf(stderr, "out of memory\n");
- X exit(1);
- X }
- X return(mem);
- X}
- X
- X/*
- X * Begin machine dependent code for mount table
- X */
- X
- X#if defined(sun)
- X#include <mntent.h>
- Xvoid
- Xmkm_mlist()
- X/*
- X * Build list of mnt entries - Sun version
- X */
- X{
- X FILE *mounted;
- X struct m_mlist *mlist;
- X struct mntent *mnt;
- X
- X if ((mounted = setmntent(MOUNTED, "r"))== NULL) {
- X perror(MOUNTED);
- X exit(1);
- X }
- X while ((mnt = getmntent(mounted)) != NULL) {
- X mlist = (struct m_mlist *)xalloc(sizeof(*mlist));
- X mlist->mlist_next = firstmnt;
- X mlist->mlist_checked = 0;
- X mlist->mlist_dir = xalloc(strlen(mnt->mnt_dir)+1);
- X (void) strcpy(mlist->mlist_dir, mnt->mnt_dir);
- X mlist->mlist_fsname = xalloc(strlen(mnt->mnt_fsname)+1);
- X (void) strcpy(mlist->mlist_fsname, mnt->mnt_fsname);
- X mlist->mlist_isnfs = !strcmp(mnt->mnt_type, MNTTYPE_NFS);
- X firstmnt = mlist;
- X }
- X (void) endmntent(mounted);
- X}
- X#endif
- X
- X#if defined(ultrix)
- X#include <sys/fs_types.h>
- X#include <sys/mount.h>
- Xvoid
- Xmkm_mlist()
- X/*
- X * Build list of mnt entries - Ultrix version (Generic File System)
- X */
- X{
- X struct m_mlist *mlist;
- X struct fs_data fs_data;
- X int start=0, len;
- X
- X while ((len = getmnt(&start, &fs_data, sizeof(fs_data),
- X NOSTAT_MANY, NULL)) > 0) {
- X mlist = (struct m_mlist *)xalloc(sizeof(*mlist));
- X mlist->mlist_next = firstmnt;
- X mlist->mlist_checked = 0;
- X mlist->mlist_dir = xalloc(strlen(fs_data.fd_path)+1);
- X (void) strcpy(mlist->mlist_dir, fs_data.fd_path);
- X mlist->mlist_fsname =
- X xalloc(strlen(fs_data.fd_devname)+1);
- X (void) strcpy(mlist->mlist_fsname, fs_data.fd_devname);
- X mlist->mlist_isnfs = (fs_data.fd_fstype == GT_NFS);
- X firstmnt = mlist;
- X }
- X if (len < 0) {
- X perror("getmnt");
- X exit(1);
- X }
- X}
- X#endif
- END_OF_FILE
- if test 13093 -ne `wc -c <'cknfs.c'`; then
- echo shar: \"'cknfs.c'\" unpacked with wrong size!
- fi
- # end of 'cknfs.c'
- fi
- echo shar: End of shell archive.
- exit 0
-